package com.michaelbulava.TFS.ui.controls.vc;


import com.intellij.debugger.ui.impl.tree.TreeBuilder;
import com.intellij.debugger.ui.impl.tree.TreeBuilderNode;
import com.intellij.openapi.project.Project;
import com.michaelbulava.TFS.Messages;
import com.michaelbulava.TFS.log.FileLogger;
import com.michaelbulava.TFS.ui.controls.generic.IProjectDependantControl;
import com.michaelbulava.TFS.ui.helpers.IconHelper;
import com.michaelbulava.TFS.vc.tfsitem.TFSFile;
import com.michaelbulava.TFS.vc.tfsitem.TFSFolder;
import com.michaelbulava.TFS.vc.tfsitem.TFSItem;
import com.michaelbulava.TFS.vc.tfsitem.TFSItemFactory;
import com.microsoft.tfs.core.clients.versioncontrol.path.ServerPath;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.DeletedState;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.ExtendedItem;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.ItemType;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;
import com.microsoft.tfs.util.Check;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;


/**
 * Created by MichaelA on 7/21/2015.
 */
public class ServerItemTreeControl extends JTree {//implements IProjectDependantControl{

    private Workspace workspace;
    private ServerItemTreeModel myModel;
    //private Project myProject;

    private boolean showDeleteItems = false;
    private boolean showFiles = false;

    public interface ServerPathSelectionChangedListener{
        void OnTreeSelectionChanged(TFSItem selection);
    }

    private ServerPathSelectionChangedListener defaultListener = new ServerPathSelectionChangedListener() {
        @Override
        public void OnTreeSelectionChanged(TFSItem selection) {

        }
    };

    private ServerPathSelectionChangedListener selectionChangedListener = defaultListener;


    public ServerItemTreeControl(){
        super();
        this.myModel = new ServerItemTreeModel();
        setModel(myModel);
        super.setCellRenderer(new ServerItemTreeRenderer());
        getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        super.addTreeWillExpandListener(new TreeWillExpandListener() {

            @Override
            public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
                if (event.getPath().getLastPathComponent() != null &&
                        event.getPath().getLastPathComponent() instanceof  ServerItemTreeNode){
                    ServerItemTreeNode currentNode = (ServerItemTreeNode) event.getPath().getLastPathComponent();
                    if (currentNode.getAllowsChildren() && currentNode.getChildCount() == 1) {
                        if (((DefaultMutableTreeNode) currentNode.getChildAt(0)).getUserObject() == null) {
                        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//                        final PopulateTreeNode worker = new PopulateTreeNode(currentNode);
//                        worker.execute();
                            //java.util.List<TFSItem> list = new ArrayList<TFSItem>();
                            if (currentNode.getTFSItem() instanceof TFSFolder){
                                TFSFolder folder = (TFSFolder) currentNode.getTFSItem();
                                Set<TFSItem> tfsItemSet = folder.getChildren(showDeleteItems);
                                Iterator<TFSItem> itemIterator= tfsItemSet.iterator();
                                while(itemIterator.hasNext()){
                                    TFSItem item = itemIterator.next();
                                    if (item instanceof TFSFile && !showFiles){
                                        continue;
                                    }
                                    //list.add(item);
                                    currentNode.add(new ServerItemTreeNode(item));
                                }
                            }
                            currentNode.remove(0);
                            //for(TFSItem item : list){
                            //    currentNode.add(new ServerItemTreeNode(item));
                            //}
                            //currentNode.remove(0);
                            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                            myModel.reload(currentNode);
                        }
                    }
                }

            }

            @Override
            public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
            }
        });

        super.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                if (e.getPath().getLastPathComponent() != null){
                    if (e.getPath().getLastPathComponent() instanceof ServerItemTreeNode){
                        selectionChangedListener.OnTreeSelectionChanged(((ServerItemTreeNode)e.getPath()
                                .getLastPathComponent()).getTFSItem());
                    }
                }
            }
        });
    }

    public TFSItem getSelectedPath(){
        if (super.getSelectionPath() != null){
            if (super.getSelectionPath().getLastPathComponent() != null){
                if (super.getSelectionPath().getLastPathComponent() instanceof ServerItemTreeNode)
                    return ((ServerItemTreeNode)super.getSelectionPath().getLastPathComponent()).getTFSItem();
            }
        }
        return null;
    }

    public void setSelectedPath(TFSItem item){
        Messages.showErrorDialog(this, "Functionality is not yet implemented.", "Work in progress");
    }

    public void setWorkspace(Workspace workspace){
        this.workspace = workspace;
        myModel.refreshTree();
    }

//    @Override
//    public void setProject(Project project) {
//        //myProject = project;
//        myModel.refreshTree();
//    }
//
//    @Override
//    public Project getProject() {
//        return myProject;
//    }

    public void setServerPathSelectionChangedListener(ServerPathSelectionChangedListener value){
        if (value == null)
            value = defaultListener;

        this.selectionChangedListener = value;
    }

    private class ServerItemTreeModel extends DefaultTreeModel {

        public ServerItemTreeModel(){
            super(null);
        }

        public void refreshTree(){
            ServerItemTreeNode root = (workspace == null) ? null :
                    new ServerItemTreeNode(TFSItemFactory.getRoot(workspace));//, getProject()));
            setRoot(root);

            if (root != null)
                ServerItemTreeControl.this.collapsePath(new TreePath(root.getPath()));
        }

    }

    private class ServerItemTreeNode extends DefaultMutableTreeNode{

        public ServerItemTreeNode(TFSItem item){
            super(item, (item instanceof TFSFolder));
            if (this.allowsChildren)
                this.add(new DefaultMutableTreeNode());
        }

        public TFSItem getTFSItem(){
            return (TFSItem)super.getUserObject();
        }
    }

    private class PopulateTreeNode extends SwingWorker<java.util.List<TFSItem>, Void>{

        private final ServerItemTreeNode parentNode;

        public PopulateTreeNode(ServerItemTreeNode parentNode){
            Check.notNull(parentNode, "parentNode");
            this.parentNode = parentNode;
        }

        @Override
        protected List<TFSItem> doInBackground() throws Exception {
            java.util.List<TFSItem> list = new ArrayList<TFSItem>();
            if (parentNode.getTFSItem() instanceof TFSFolder){
                TFSFolder folder = (TFSFolder) parentNode.getTFSItem();
                Set<TFSItem> tfsItemSet = folder.getChildren(showDeleteItems);
                Iterator<TFSItem> itemIterator= tfsItemSet.iterator();
                while(itemIterator.hasNext()){
                    TFSItem item = itemIterator.next();
                    if (item instanceof TFSFile && !showFiles){
                        continue;
                    }
                    list.add(item);
                }
            }
            return list;
        }

        @Override
        protected void done() {
            try {
                java.util.List<TFSItem> list = get();
                for(TFSItem item : list){
                    parentNode.add(new ServerItemTreeNode(item));
                }
            } catch (Exception ignore) {
                FileLogger.getInstance(ServerItemTreeControl.class).error(ignore);
            } finally {
                parentNode.remove(0);
                setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                myModel.reload(parentNode);
            }
        }
    }

    private class ServerItemTreeRenderer extends DefaultTreeCellRenderer {

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
                                                      boolean leaf, int row, boolean hasFocus) {
            String displayValue;
            TFSItem item = null;
            if (value instanceof ServerItemTreeNode){
                item = ((ServerItemTreeNode) value).getTFSItem();
                displayValue = item.getName();
            } else if (value instanceof DefaultMutableTreeNode){
                displayValue = "Loading...";
            } else {
                displayValue="<Unknown Item>";
            }

//            JLabel label = new JLabel(displayValue);
//            if (selected){
//                label.setForeground(tree.getForeground());
//                tree.getSelection
//            }
            Component c = super.getTreeCellRendererComponent(tree, displayValue,
                    selected, expanded, leaf, row, hasFocus);
//            Icon icon = null;
//            if (item != null){
//                icon = IconHelpers.getIconForTFSItem(item);
//            }
//            component.setIcon(icon);
            setIcon(IconHelper.getIconForTFSItem(item));
            return c;
        }
    }
}
